package com.youlu.myapplication.scratch;

import android.annotation.SuppressLint;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.youlu.myapplication.R;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;

/**
 * @author : YOULU  sym
 * date   : 2020/11/29 0029
 * desc   : 画板页面
 */
public class ScratchFragment extends Fragment
        implements View.OnTouchListener,
        ScratchView.ScratchCallBack,
        ViewTreeObserver.OnGlobalLayoutListener {

    private static String TAG = "ScratchFragment";
    private boolean DEBUG = true;

    public static final Path mEmptyPath = new Path();
    public static final List<float[]> b = new LinkedList();
    public List<float[]> mPathCache;
    public boolean mLock = true;

    /**
     * 画布
     */
    public ScratchView mScratchView;
    /**
     * 画笔
     */
    public Paint mPaint;
    public List<Path> mPaths;
    public Path mPath;
    /**
     * path的 X 轴起点坐标
     */
    private float mStartXPoint;
    /**
     * path的 Y 轴起点坐标
     */
    private float mStartYPoint;
    /**
     * 记录坐标点
     */
    private List<float[]> mCoordinatePoints;
    /**
     * 记录path的数量
     */
    public int mCurrentPathSize;
    private boolean fake_bar_enable = false;
    private String unique_id;
    /**
     * 移动的最小有效距离
     */
    private int slop;
    private ImageView barUndoView;
    private ImageView barDeleteView;
    private ImageView barRedoView;
    public boolean mFlag = true;
    public LinearLayout mLinearLayout;
    private float w;
    private float x;
    private float y;
    private float z;
    /**
     * 当前状态 默认值为0
     * 1：单手指
     * 2：多手指
     */
    public int mType = 0;
    /**
     * 记录每条线的坐标系
     */
    public List<List<float[]>> mCoordinatePointsList;

    public Pair<Pair<Integer, Integer>, Pair<CoordinatePoint[], Integer>> mPathInMemory;

    BothWayScrollView scratchScroll;

    public BothWayScrollView.a B = new BothWayScrollView.a() {
        @Override
        public void a() {
            ScratchFragment.this.invalidate();
        }
    };

    /**
     * 通知UI 重绘
     */
    public void invalidate() {
        mScratchView.invalidate();
    }

    public static Bundle newBundle(String str, boolean z2) {
        Bundle bundle = new Bundle();
        bundle.putString("id.unique", str);
        bundle.putBoolean("fake.bar.enable", z2);
        return bundle;
    }


    public static ScratchFragment createFragment(String str, boolean z2) {
        ScratchFragment scratchFragment = new ScratchFragment();
        scratchFragment.setArguments(newBundle(str, z2));
        return scratchFragment;
    }

    @Override
    public void onActivityCreated(Bundle bundle) {
        super.onActivityCreated(bundle);
        if (getArguments() != null) {
            fake_bar_enable = getArguments().getBoolean("fake.bar.enable");
            unique_id = getArguments().getString("id.unique");
        }
        /*if (getActivity() instanceof Activity) {
            ((FbActivity) getActivity()).a((FbActivity.a) new FbActivity.a() {
                public boolean onBackPressed() {
                    ScratchFragment.this.t();
                    dde.a((Fragment) ScratchFragment.this, alh.a.pop_out_up_down);
                    return true;
                }
            });
        }*/
        init();
    }

    public void saveData() {
        LinkedList<CoordinatePoint> linkedList = new LinkedList<>();
        for (List<float[]> next : mCoordinatePointsList) {
            CoordinatePoint coordinatePoint = new CoordinatePoint();
            LinkedList<Float> linkedList2 = new LinkedList<>();
            LinkedList<Float> linkedList3 = new LinkedList<>();

            for (float[] next2 : next) {
                linkedList2.add(next2[0]);
                linkedList3.add(next2[1]);
            }
            coordinatePoint.saveCoordinateX(linkedList2);
            coordinatePoint.saveCoordinateY(linkedList3);
            linkedList.add(coordinatePoint);
        }
        ScratchInnerclass
                .newInstance()
                .save(unique_id,
                        scratchScroll.getScrollX(),
                        scratchScroll.getScrollY(),
                        linkedList.toArray(new CoordinatePoint[0]),
                        mCurrentPathSize);
    }


    @Override
    public void onResume() {
        super.onResume();
        getView().setFocusableInTouchMode(true);
        getView().requestFocus();
        getView().setOnKeyListener((v, keyCode, event) -> {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {

                // handle back button
                if (DEBUG) {
                    Log.i(TAG, "the back key is pressed");
                }

                saveData();
                getActivity().finish();

                return true;
            }
            return false;

        });
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = getView(getLayoutInflater(), container, savedInstanceState);
        barRedoView = view.findViewById(R.id.bar_redo_view);
        barDeleteView = view.findViewById(R.id.bar_delete_view);
        barUndoView = view.findViewById(R.id.bar_undo_view);
        scratchScroll = view.findViewById(R.id.scroll_scratch);
        return view;
    }

    /**
     * 获取当前页面加载的View
     */
    public View getView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {
        return layoutInflater.inflate(getLayout(), viewGroup, false);
    }

    /**
     * 获取布局文件
     *
     * @return 返回布局文件的id
     */
    private int getLayout() {
        return R.layout.question_scratch_fragment;
    }


    private void init() {
//        this.fakeBar.setVisibility(this.k ? 0 : 8);
        this.mPathInMemory = ScratchInnerclass.newInstance().memorySearch(unique_id);
        this.scratchScroll.getViewTreeObserver().addOnGlobalLayoutListener(this);
        this.slop = hv.getScaledPagingTouchSlop(ViewConfiguration.get(getActivity())) / 4;
        this.mPaint = new Paint();
        this.mPaint.setAntiAlias(true);
        this.mPaint.setDither(true);
        this.mPaint.setColor(getResources().getColor(R.color.bg_scratch));
        this.mPaint.setStyle(Paint.Style.STROKE);
        this.mPaint.setStrokeCap(Paint.Cap.ROUND);
        this.mPaint.setStrokeJoin(Paint.Join.ROUND);
        this.mPaint.setStrokeWidth(4.0f);
        onInit();
    }

    public void delete() {
        if (mCurrentPathSize < mPaths.size()) {
            mPaths.set(mCurrentPathSize, mEmptyPath);
            mCoordinatePointsList.set(mCurrentPathSize, b);
            mPathCache.set(mCurrentPathSize, new float[0]);
            mCurrentPathSize++;
            mPaths = mPaths.subList(0, mCurrentPathSize);
            mCoordinatePointsList = mCoordinatePointsList.subList(0, mCurrentPathSize);
            mPathCache = mPathCache.subList(0, mCurrentPathSize);
        } else if (mCurrentPathSize == mPaths.size()) {
            mPaths.add(mEmptyPath);
            mCoordinatePointsList.add(b);
            mPathCache.add(new float[0]);
            mCurrentPathSize++;
        } else {
            mPaths.add(mEmptyPath);
            mCoordinatePointsList.add(b);
            mPathCache.add(new float[0]);
            mCurrentPathSize = mPaths.size();
        }
        invalidate();
        setButtonViewEnabled(mPaths.size(), mCurrentPathSize, safeVerify());
    }

    /**
     * 重新绘制
     */
    public void redo() {
        if (this.mCurrentPathSize < mPaths.size()) {
            mCurrentPathSize++;
            setButtonViewEnabled(this.mPaths.size(), mCurrentPathSize, safeVerify());
            invalidate();
        }
    }

    /**
     * 撤销绘制
     */
    public void undo() {

        if (mCurrentPathSize > 0) {
            mCurrentPathSize--;
            setButtonViewEnabled(mPaths.size(), mCurrentPathSize, safeVerify());
            invalidate();
        }
    }


    /**
     * 从缓存中恢复
     */
    public void resetFromCache() {
        CoordinatePoint[] almArr;
        float f2 = 0;
        float f3 = 0;
        float f4 = 0;
        CoordinatePoint[] almArr2;
        int i2;
        Pair<Pair<Integer, Integer>, Pair<CoordinatePoint[], Integer>> pair = mPathInMemory;
        //此处有删除
        if (!(pair == null || pair.second == null)) {
            CoordinatePoint[] almArr3 = this.mPathInMemory.second.first;
            int length = almArr3.length;
            int i3 = 0;
            while (true) {
                int i4 = 1;
                if (i3 >= length) {
                    break;
                }
                CoordinatePoint alm = almArr3[i3];
                Path path = new Path();
                List linkedList = new LinkedList();
                float f5 = -1.0f;
                if (alm.getCoordinateX() == null) {
                    path = mEmptyPath;
                    linkedList = b;
                    almArr = almArr3;
                    f4 = -1.0f;
                    f3 = -1.0f;
                    f2 = -1.0f;
                } else {
                    float[] a2 = alm.getCoordinateX();
                    float[] b2 = alm.getCoordinateY();
                    if (a2.length != b2.length) {
                        almArr = almArr3;
                        i3++;
                        almArr3 = almArr;
                    } else {
                        int i5 = 0;
                        float f6 = -1.0f;
                        f4 = -1.0f;
                        f3 = -1.0f;
                        f2 = -1.0f;
                        while (i5 < a2.length) {
                            if (i5 == 0) {
                                path.moveTo(a2[i5], b2[i5]);
                                almArr2 = almArr3;
                                f3 = a2[i5];
                                f4 = b2[i5];
                                f2 = f4;
                                i2 = 2;
                                f6 = f3;
                            } else {
                                if (i5 == a2.length - i4) {
                                    path.lineTo(a2[i5], b2[i5]);
                                    almArr2 = almArr3;
                                } else {
                                    int i6 = i5 - 1;
                                    almArr2 = almArr3;
                                    path.quadTo(a2[i6], b2[i6], (a2[i6] + a2[i5]) / 2.0f, (b2[i6] + b2[i5]) / 2.0f);
                                }
                                float min = Math.min(f6, a2[i5]);
                                f6 = min;
                                f4 = Math.min(f4, b2[i5]);
                                f3 = Math.max(f3, a2[i5]);
                                f2 = Math.max(f2, b2[i5]);
                                i2 = 2;
                            }
                            float[] fArr = new float[i2];
                            fArr[0] = a2[i5];
                            fArr[1] = b2[i5];
                            linkedList.add(fArr);
                            i5++;
                            almArr3 = almArr2;
                            i4 = 1;
                        }
                        almArr = almArr3;
                        f5 = f6;
                    }
                }
                mPaths.add(path);
                mCoordinatePointsList.add(linkedList);
                mPathCache.add(new float[]{f5, f4, f3, f2});
                mCurrentPathSize++;
                i3++;
                almArr3 = almArr;
            }
            mCurrentPathSize = mPathInMemory.second.second;
            int scratchScrollX = mPathInMemory.first.first;
            int scratchScrollY = mPathInMemory.first.second;
            mLock = true;
            scratchScroll.postDelayed(() -> scratchScroll.scrollTo(scratchScrollX, scratchScrollY), 300);
        }
        setButtonViewEnabled(mPaths.size(), mCurrentPathSize, safeVerify());
    }


    static int a(ScratchFragment arg0, int arg1) {
        arg0.mType = arg1;
        return arg1;
    }


    /**
     * 处理移动事件
     *
     * @param x x轴坐标
     * @param y y轴坐标
     */
    public void handleActionMove(float x, float y) {
        //x轴滑动距离
        float abs = Math.abs(x - mStartXPoint);
        //y轴滑动距离
        float abs2 = Math.abs(y - mStartYPoint);
        //如果X轴和Y轴移动的距离小于最小有效距离就判定为无效移动
        if (abs < ((float) slop) && abs2 < ((float) slop)) {
            return;
        }
        if (mPath == null || safeVerityCollection(mCoordinatePoints)) {
            initPath(x, y);
            return;
        }
        //贝塞尔曲线
        mPath.quadTo(mStartXPoint, mStartYPoint, (x + mStartXPoint) / 2.0f, (y + mStartYPoint) / 2.0f);
        mCoordinatePoints.add(new float[]{(mStartXPoint + x) / 2.0f, (mStartYPoint + y) / 2.0f});
        mStartXPoint = x;
        mStartYPoint = y;
        w = Math.min(this.w, (mStartXPoint + x) / 2.0f);
        x = Math.min(this.x, (mStartYPoint + y) / 2.0f);
        y = Math.max(this.y, (x + mStartXPoint) / 2.0f);
        z = Math.max(this.z, (y + mStartYPoint) / 2.0f);
    }

    /**
     * 校验collection
     *
     * @param collection 目标集合
     * @return
     */
    public static boolean safeVerityCollection(Collection<?> collection) {
        return collection == null || collection.size() == 0;
    }

    /**
     * @param x x轴坐标点
     * @param y y轴坐标点
     */
    public void initPath(float x, float y) {
        this.mPath = new Path();
        this.mCoordinatePoints = new LinkedList();
        //移动画笔到指定位置
        this.mPath.moveTo(x, y);
        this.mCoordinatePoints.add(new float[]{x, y});
        this.mStartXPoint = x;
        this.mStartYPoint = y;
        this.w = x;
        this.y = x;
        this.x = y;
        this.z = y;
    }

    public void onActionUp() {
        if (mPath != null && mCoordinatePoints != null) {
            mPath.lineTo(mStartXPoint, mStartYPoint);
            mCoordinatePoints.add(new float[]{mStartXPoint, mStartYPoint});
            if (mCoordinatePoints.size() < 3) {
                reset();
                return;
            }
            if (mCurrentPathSize < mPaths.size()) {
                mPaths.set(mCurrentPathSize, mPath);
                mCoordinatePointsList.set(mCurrentPathSize, mCoordinatePoints);
                mPathCache.set(mCurrentPathSize, new float[]{this.w, this.x, this.y, this.z});
                mCurrentPathSize++;
                mPaths = mPaths.subList(0, mCurrentPathSize);
                mCoordinatePointsList = mCoordinatePointsList.subList(0, mCurrentPathSize);
                mPathCache = mPathCache.subList(0, mCurrentPathSize);
            } else if (mCurrentPathSize == mPaths.size()) {
                mPaths.add(mPath);
                mCoordinatePointsList.add(mCoordinatePoints);
                mPathCache.add(new float[]{this.w, this.x, this.y, this.z});
                mCurrentPathSize++;
            } else {
                mPaths.add(mPath);
                mCoordinatePointsList.add(mCoordinatePoints);
                mPathCache.add(new float[]{this.w, this.x, this.y, this.z});
                mCurrentPathSize = mPaths.size();
            }
            setButtonViewEnabled(mPaths.size(), mCurrentPathSize, safeVerify());
            reset();
        }
    }

    /**
     * 设置View的是否可点击状态
     *
     * @param size            当前集合中的path 的数量
     * @param currentPathSize
     * @param flag
     */
    private void setButtonViewEnabled(int size, int currentPathSize, boolean flag) {
        boolean enabled = true;
        this.barDeleteView.setEnabled(currentPathSize > 0 && !flag);
        this.barUndoView.setEnabled(currentPathSize > 0);
        ImageView imageView = this.barRedoView;
        if (currentPathSize >= size) {
            enabled = false;
        }
        imageView.setEnabled(enabled);
    }


    /**
     * 重置
     */
    public void reset() {
        this.mPath = null;
        this.mCoordinatePoints = null;
    }

    /**
     * 安全校验
     *
     * @return 返回校验结果
     */
    private boolean safeVerify() {

        if (mCurrentPathSize != 0
                && mPaths.get(mCurrentPathSize - 1) == mEmptyPath) {

            return true;
        }
        return false;
    }


    private void onInit() {
//        this.fakeBar.setBackgroundResource(alh.b.scratch_bar_bg);
//        this.scratchActionBar.setBackgroundResource(alh.b.scratch_bar_bg);
        ImageView imageView = this.barUndoView;
        imageView.setImageResource(imageView.isEnabled() ? R.mipmap.scratch_bar_undo : R.mipmap.scratch_bar_undo_disable);
        ImageView imageView2 = this.barDeleteView;
        imageView2.setImageResource(imageView2.isEnabled() ? R.mipmap.scratch_bar_delete : R.mipmap.scratch_bar_delete_disable);
        ImageView imageView3 = this.barRedoView;
        imageView3.setImageResource(imageView3.isEnabled() ? R.mipmap.scratch_bar_redo : R.mipmap.scratch_bar_redo_disable);
    }


    @Override
    public void onGlobalLayout() {

        if (mFlag) {
            mFlag = false;
            final int measuredWidth = scratchScroll.getMeasuredWidth();
            final int measuredHeight = scratchScroll.getMeasuredHeight();
            if (DEBUG) {
                Log.i(TAG, "measuredWidth : " + measuredWidth + " measuredHeight : " + measuredHeight);
            }
            mLinearLayout = new LinearLayout(getActivity());
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            mScratchView = new ScratchView(getActivity());
            /**
             * 设置画板的大小
             */
            mScratchView.setLayoutParams(new LinearLayout.LayoutParams(measuredWidth * 5, measuredHeight * 5));

            mLinearLayout.addView(mScratchView);
            scratchScroll.addView(mLinearLayout, layoutParams);
            if (mPathInMemory == null || !(mPathInMemory == null || mPathInMemory.second == null || ((Pair) mPathInMemory.second).first == null || ((CoordinatePoint[]) ((Pair) ScratchFragment.this.mPathInMemory.second).first).length != 0)) {
                ScratchFragment.this.scratchScroll.postDelayed(() -> ScratchFragment.this.scratchScroll.a(measuredWidth, measuredHeight), 300);
            }
            mLinearLayout.setOnTouchListener(this);

            //设置 按钮的点击事件
            barRedoView.setOnClickListener(v -> redo());

            barUndoView.setOnClickListener(v -> undo());

            barDeleteView.setOnClickListener(v -> delete());


            ScratchFragment.this.B.a(scratchScroll);
            mScratchView.setScratchCallBack(this);
            mLinearLayout.setBackgroundResource(R.color.bg_scratch);

            mPaths = new ArrayList<>();
            mCoordinatePointsList = new LinkedList<>();
            mPathCache = new LinkedList<>();

            resetFromCache();
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent motionEvent) {

        float x = motionEvent.getX();
        float y = motionEvent.getY();
        //
        scratchScroll.requestDisallowInterceptTouchEvent(true);
        int action = motionEvent.getAction() & MotionEvent.ACTION_MASK;
        if (DEBUG) {
            Log.i(TAG, "action ==== " + action);
        }
        if (action == MotionEvent.ACTION_DOWN) {
            if (DEBUG) {
                Log.i(TAG, "ACTION_DOWN");
            }
            mType = 1;
            initPath(x, y);
            invalidate();
        } else if (action == MotionEvent.ACTION_UP) {
            if (DEBUG) {
                Log.i(TAG, "ACTION_UP");
            }
            if (mType == 1) {
                onActionUp();
                invalidate();
            }
            mType = mType - 1;
        } else if (action == MotionEvent.ACTION_MOVE) {
            if (DEBUG) {
                Log.i(TAG, "ACTION_MOVE");
            }
            if (mType == 1) {
                handleActionMove(x, y);
                invalidate();
                return true;
            } else if (mType == 2) {
                scratchScroll.requestDisallowInterceptTouchEvent(false);
                return false;
            }

        } else {
            if (action == MotionEvent.ACTION_POINTER_DOWN) {
                if (DEBUG) {
                    Log.i(TAG, "ACTION_POINTER_DOWN");
                }
                reset();
                mType = mType + 1;
            } else if (action == MotionEvent.ACTION_POINTER_UP) {
                if (DEBUG) {
                    Log.i(TAG, "ACTION_POINTER_UP");
                }
                mType = mType - 1;
            }
        }
        return true;
    }

    @Override
    public Paint getPaint() {
        return mPaint;
    }

    @Override
    public List<Path> getPaths() {
        return mPaths;
    }

    @Override
    public Path path() {
        return mPath;
    }

    @Override
    public int getCurrentPathSize() {
        return mCurrentPathSize;
    }

    @Override
    public List<Boolean> onDraw() {

        List<Boolean> linkedList = new LinkedList<Boolean>();
        float scrollX = (float) scratchScroll.getScrollX();
        float scrollY = (float) scratchScroll.getScrollY();
        if (mLock) {
            mLock = false;
            if (mPathInMemory != null) {
                scrollX = (float) mPathInMemory.first.first;
                scrollY = mPathInMemory.first.second;
            } else {
                scrollX = (float) scratchScroll.getMeasuredWidth();
                scrollY = scratchScroll.getMeasuredHeight();
            }
        }
        float measuredWidth = ((float) scratchScroll.getMeasuredWidth()) + scrollX;
        float measuredHeight = ((float) scratchScroll.getMeasuredHeight()) + scrollY;
        for (int i = 0; i < mPaths.size(); i++) {
            boolean flag = true;
            if (i >= mPathCache.size() || mPathCache.get(i).length < 4) {
                linkedList.add(true);
            } else {
                float f = mPathCache.get(i)[0];
                float f2 = mPathCache.get(i)[1];
                float f3 = mPathCache.get(i)[2];
                float f4 = mPathCache.get(i)[3];
                if (Math.max(scrollX, f) > Math.min(measuredWidth, f3) || Math.max(scrollY, f2) > Math.min(measuredHeight, f4)) {
                    flag = false;
                }
                linkedList.add(flag);
            }
        }
        return linkedList;
    }


    public static class ScratchInnerclass {
        private static ScratchInnerclass instance;

        private ScratchInnerclass() {
        }

        public static ScratchInnerclass newInstance() {
            if (instance == null) {
                synchronized (ScratchInnerclass.class) {
                    if (instance == null) {
                        instance = new ScratchInnerclass();
                    }
                }
            }
            return instance;
        }

        public Pair<Pair<Integer, Integer>, Pair<CoordinatePoint[], Integer>> memorySearch(String str) {
            ScratchData scratchData = ScratchUtils.getScratchData("business_question", format(str), ScratchData.class);
            if (scratchData == null) {
                return null;
            }
            return new Pair<>(new Pair(scratchData.scratchScrollX, scratchData.scratchScrollY), new Pair(scratchData.paths, scratchData.nextStroke));
        }

        public boolean save(String str, int scratchScrollX, int scratchScrollY, CoordinatePoint[] almArr, int nextStroke) {
            ScratchUtils.save("business_question", format(str), new ScratchData(scratchScrollX, scratchScrollY, almArr, nextStroke));
            return true;
        }

        public boolean remove(String str) {
            ScratchUtils.remove("business_question", format(str));
            return true;
        }

        private static String format(String str) {
            return String.format("scratch_data_%s", str);
        }
    }


    static class ScratchData extends BaseData {
        int nextStroke;
        CoordinatePoint[] paths;
        int scratchScrollX;
        int scratchScrollY;

        public ScratchData(int scratchScrollX, int scratchScrollY, CoordinatePoint[] almArr, int nextStroke) {
            this.scratchScrollX = scratchScrollX;
            this.scratchScrollY = scratchScrollY;
            this.paths = almArr;
            this.nextStroke = nextStroke;
        }
    }
}
